package com.caoustc.okhttplib.okhttp

import com.caoustc.okhttplib.utils.StringUtils
import okhttp3.*
import okio.Buffer
import java.io.InputStream
import java.net.Proxy
import java.util.*
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLSocketFactory

class OkHttpConfiguration private constructor(builder: Builder) {
    val commonParams: MutableList<Part>?
    var commonHeaders: Headers?
    val certificateList: List<InputStream>
    val hostnameVerifier: HostnameVerifier?
    var timeout = OkHttpConstants.REQ_TIMEOUT.toLong()
    val isDebug: Boolean
    val cookieJar: CookieJar
    val cache: Cache?
    val authenticator: Authenticator?
    val certificatePinner: CertificatePinner?
    val isFollowSslRedirects: Boolean
    val isFollowRedirects: Boolean
    val isRetryOnConnectionFailure: Boolean
    val proxy: Proxy?
    val networkInterceptorList: List<Interceptor>
    val interceptorList: List<Interceptor>?
    val sslSocketFactory: SSLSocketFactory?
    val dispatcher: Dispatcher?

    class Builder {
        var commonParams: MutableList<Part>? = null
        var commonHeaders: Headers? = null
        val certificateList: MutableList<InputStream>
        var hostnameVerifier: HostnameVerifier? = null
        var timeout: Long = 0
        var debug = false
        var cookieJar = CookieJar.NO_COOKIES
        var cache: Cache? = null
        var authenticator: Authenticator? = null
        var certificatePinner: CertificatePinner? = null
        var followSslRedirects: Boolean
        var followRedirects: Boolean
        var retryOnConnectionFailure: Boolean
        var proxy: Proxy? = null
        val networkInterceptorList: MutableList<Interceptor>
        var interceptorList: List<Interceptor>? = null
        var sslSocketFactory: SSLSocketFactory? = null
        var dispatcher: Dispatcher? = null
        fun setCommenParams(params: MutableList<Part>?): Builder {
            commonParams = params
            return this
        }

        fun setCommenHeaders(headers: Headers?): Builder {
            commonHeaders = headers
            return this
        }

        fun setCertificates(vararg certificates: InputStream?): Builder {
            for (inputStream in certificates) {
                if (inputStream != null) {
                    certificateList.add(inputStream)
                }
            }
            return this
        }

        fun setCertificates(vararg certificates: String?): Builder {
            for (certificate in certificates) {
                if (!StringUtils.Companion.isEmpty(certificate)) {
                    certificateList.add(
                        Buffer()
                            .writeUtf8(certificate)
                            .inputStream()
                    )
                }
            }
            return this
        }

        fun setHostnameVerifier(hostnameVerifier: HostnameVerifier?): Builder {
            this.hostnameVerifier = hostnameVerifier
            return this
        }

        fun setCertificatePinner(certificatePinner: CertificatePinner?): Builder {
            this.certificatePinner = certificatePinner
            return this
        }

        fun setDebug(debug: Boolean): Builder {
            this.debug = debug
            return this
        }

        fun setTimeout(timeout: Long): Builder {
            this.timeout = timeout
            return this
        }

        fun setCookieJar(cookieJar: CookieJar): Builder {
            this.cookieJar = cookieJar
            return this
        }

        fun setCache(cache: Cache?): Builder {
            this.cache = cache
            return this
        }

        fun setCacheAge(cache: Cache?, cacheTime: Int): Builder {
            setCache(cache, String.format("max-age=%d", cacheTime))
            return this
        }

        fun setCacheStale(cache: Cache?, cacheTime: Int): Builder {
            setCache(cache, String.format("max-stale=%d", cacheTime))
            return this
        }

        fun setCache(cache: Cache?, cacheControlValue: String?): Builder {
            val REWRITE_CACHE_CONTROL_INTERCEPTOR = Interceptor { chain ->
                val originalResponse = chain.proceed(chain.request())
                originalResponse.newBuilder()
                    .removeHeader("Pragma")
                    .header("Cache-Control", cacheControlValue)
                    .build()
            }
            networkInterceptorList.add(REWRITE_CACHE_CONTROL_INTERCEPTOR)
            this.cache = cache
            return this
        }

        fun setAuthenticator(authenticator: Authenticator?): Builder {
            this.authenticator = authenticator
            return this
        }

        fun setFollowSslRedirects(followProtocolRedirects: Boolean): Builder {
            followSslRedirects = followProtocolRedirects
            return this
        }

        fun setFollowRedirects(followRedirects: Boolean): Builder {
            this.followRedirects = followRedirects
            return this
        }

        fun setRetryOnConnectionFailure(retryOnConnectionFailure: Boolean): Builder {
            this.retryOnConnectionFailure = retryOnConnectionFailure
            return this
        }

        fun setProxy(proxy: Proxy?): Builder {
            this.proxy = proxy
            return this
        }

        fun setNetworkInterceptors(interceptors: List<Interceptor>?): Builder {
            if (interceptors != null) {
                networkInterceptorList.addAll(interceptors)
            }
            return this
        }

        fun setInterceptors(interceptors: List<Interceptor>?): Builder {
            interceptorList = interceptors
            return this
        }

        fun setSSLSocketFactory(sslSocketFactory: SSLSocketFactory?): Builder {
            this.sslSocketFactory = sslSocketFactory
            return this
        }

        fun setDispatcher(dispatcher: Dispatcher?): Builder {
            this.dispatcher = dispatcher
            return this
        }

        fun build(): OkHttpConfiguration {
            return OkHttpConfiguration(this)
        }

        init {
            certificateList = ArrayList()
            followSslRedirects = true
            followRedirects = true
            retryOnConnectionFailure = true
            networkInterceptorList = ArrayList()
        }
    }

    init {
        commonParams = builder.commonParams
        commonHeaders = builder.commonHeaders
        certificateList = builder.certificateList
        hostnameVerifier = builder.hostnameVerifier
        timeout = builder.timeout
        isDebug = builder.debug
        cookieJar = builder.cookieJar
        cache = builder.cache
        authenticator = builder.authenticator
        certificatePinner = builder.certificatePinner
        isFollowSslRedirects = builder.followSslRedirects
        isFollowRedirects = builder.followRedirects
        isRetryOnConnectionFailure = builder.retryOnConnectionFailure
        proxy = builder.proxy
        networkInterceptorList = builder.networkInterceptorList
        interceptorList = builder.interceptorList
        sslSocketFactory = builder.sslSocketFactory
        dispatcher = builder.dispatcher
    }
}